/*
** $Id: lvm.h,v 2.41.1.1 2017/04/19 17:20:42 roberto Exp $
** Lua virtual machine
** See Copyright Notice in lua.h
*/

#ifndef lvm_h
#define lvm_h

#include "ldo.h"
#include "lobject.h"
#include "ltm.h"

#if !defined(LUA_NOCVTN2S)
#define cvt2str(o) ttisnumber(o)
#else
#define cvt2str(o) 0 /* no conversion from numbers to strings */
#endif

#if !defined(LUA_NOCVTS2N)
#define cvt2num(o) ttisstring(o)
#else
#define cvt2num(o) 0 /* no conversion from strings to numbers */
#endif

/*
** You can define LUA_FLOORN2I if you want to convert floats to integers
** by flooring them (instead of raising an error if they are not
** integral values)
*/
#if !defined(LUA_FLOORN2I)
#define LUA_FLOORN2I 0
#endif

#define tonumber(o, n) \
  (ttisfloat(o) ? (*(n) = fltvalue(o), 1) : luaV_tonumber_(o, n))

#define tointeger(o, i) \
  (ttisinteger(o) ? (*(i) = ivalue(o), 1) : luaV_tointeger(o, i, LUA_FLOORN2I))

#define intop(op, v1, v2) l_castU2S(l_castS2U(v1) op l_castS2U(v2))

#define luaV_rawequalobj(t1, t2) luaV_equalobj(NULL, t1, t2)

/*
** fast track for 'gettable': if 't' is a table and 't[k]' is not nil,
** return 1 with 'slot' pointing to 't[k]' (final result).  Otherwise,
** return 0 (meaning it will have to check metamethod) with 'slot'
** pointing to a nil 't[k]' (if 't' is a table) or NULL (otherwise).
** 'f' is the raw get function to use.
*/
#define luaV_fastget(L, t, k, slot, f)                                              \
  (!ttistable(t)                                                                    \
       ? (slot = NULL, 0)         /* not a table; 'slot' is NULL and result is 0 */ \
       : (slot = f(hvalue(t), k), /* else, do raw access */                         \
          !ttisnil(slot)))        /* result not nil? */

/*
** standard implementation for 'gettable'
*/
#define luaV_gettable(L, t, k, v)              \
  {                                            \
    const TValue *slot;                        \
    if (luaV_fastget(L, t, k, slot, luaH_get)) \
    {                                          \
      setobj2s(L, v, slot);                    \
    }                                          \
    else                                       \
      luaV_finishget(L, t, k, v, slot);        \
  }

/*
** Fast track for set table. If 't' is a table and 't[k]' is not nil,
** call GC barrier, do a raw 't[k]=v', and return true; otherwise,
** return false with 'slot' equal to NULL (if 't' is not a table) or
** 'nil'. (This is needed by 'luaV_finishget'.) Note that, if the macro
** returns true, there is no need to 'invalidateTMcache', because the
** call is not creating a new entry.
*/
#define luaV_fastset(L, t, k, slot, f, v)                        \
  (!ttistable(t)                                                 \
       ? (slot = NULL, 0)                                        \
       : (slot = f(hvalue(t), k),                                \
          ttisnil(slot) ? 0                                      \
                        : (luaC_barrierback(L, hvalue(t), v),    \
                           setobj2t(L, cast(TValue *, slot), v), \
                           1)))

#define luaV_settable(L, t, k, v)                  \
  {                                                \
    const TValue *slot;                            \
    if (!luaV_fastset(L, t, k, slot, luaH_get, v)) \
      luaV_finishset(L, t, k, v, slot);            \
  }

LUAI_FUNC int luaV_equalobj(lua_State *L, const TValue *t1, const TValue *t2);
LUAI_FUNC int luaV_lessthan(lua_State *L, const TValue *l, const TValue *r);
LUAI_FUNC int luaV_lessequal(lua_State *L, const TValue *l, const TValue *r);
LUAI_FUNC int luaV_tonumber_(const TValue *obj, lua_Number *n);
LUAI_FUNC int luaV_tointeger(const TValue *obj, lua_Integer *p, int mode);
LUAI_FUNC void luaV_finishget(lua_State *L, const TValue *t, TValue *key,
                              StkId val, const TValue *slot);
LUAI_FUNC void luaV_finishset(lua_State *L, const TValue *t, TValue *key,
                              StkId val, const TValue *slot);
LUAI_FUNC void luaV_finishOp(lua_State *L);
LUAI_FUNC void luaV_execute(lua_State *L);
LUAI_FUNC void luaV_concat(lua_State *L, int total);
LUAI_FUNC lua_Integer luaV_div(lua_State *L, lua_Integer x, lua_Integer y);
LUAI_FUNC lua_Integer luaV_mod(lua_State *L, lua_Integer x, lua_Integer y);
LUAI_FUNC lua_Integer luaV_shiftl(lua_Integer x, lua_Integer y);
LUAI_FUNC void luaV_objlen(lua_State *L, StkId ra, const TValue *rb);

#endif
